package net.ak.session;

import java.util.Date;
import java.util.Hashtable;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import net.ak.constant.Constant;
import net.ak.model.User;
import net.ak.utils.EncriptUtils;

public class SessionManagerment {
	private final static SessionManagerment INSTANCE 	= new SessionManagerment();
	private Hashtable<String, UserTO>		sessions	= new Hashtable<String, UserTO>();
	private final static EncriptUtils		encript		= EncriptUtils.getInstance();
	
	private String errorCode 	= "";
	private String errorMessage = "";
	
	private SessionManagerment() {}
	
	public static SessionManagerment getInstance() {
		return INSTANCE;
	}
	
	/**
	 * This method is used to track session
	 */
	public synchronized void trackSession() {
		for (Map.Entry<String, UserTO> entry : sessions.entrySet()) {
			String email 	= entry.getKey();
			boolean expired = isExpired(email);
			if (expired) {
				//update isOnline in the database.
				//sessions.remove(email);
			}
		}
	}

	/**
	 * This method is used to get user info in map
	 * 
	 * @param key - email
	 * @return
	 */
	public UserTO getUser(String key) {
		return sessions.get(key);
	}

	/**
	 * This method is used to update last operation based on key
	 * @param key - email
	 */
	public void updateLastOperation(String key) {
		UserTO to = getUser(key);
		if (null == to) return;
		to.setLastOperation(new Date());
	}
	
	/**
	 * This method is used to initiate session with user information
	 * @param user
	 */
	public synchronized String initSession(User user){
		String session 	= user.getEmail() + "-;-" + System.currentTimeMillis();
		session 		= encript.encrypt(session);
		
		UserTO to 		= new UserTO();
		to.setUser(user);
		to.setSession(session);
		to.setLastOperation(new Date());
		
		sessions.put(user.getEmail(), to);
		return session;
	}
	
	/**
	 * This method is used to check session is expired or not
	 * @param key - email.
	 * @return
	 */
	public boolean isExpired(String key) {
		UserTO to 		= getUser(key);
		Long diff 		= getDateDiff(new Date(), to.getLastOperation(), TimeUnit.SECONDS);
		boolean x = diff >= 20;
		System.out.println("Time leff -> " + diff + "isEx:" + x);
		return diff >= 300;
	}
	
	/**
	 * This method is used to check user active or not active.
	 * @param key - email
	 * @return
	 */
	public boolean isActive(String key) {
		UserTO to 		= getUser(key);
		if (null == to) return false;
		if (to != null && isExpired(key)) return false;
		return true;
	}
	
	/**
	 * This method is used to calculate duration between 2 dates
	 * @param date1
	 * @param date2
	 * @param timeUnit
	 * @return
	 */
	private long getDateDiff(Date date1, Date date2, TimeUnit timeUnit) {
	    long diffInMillies =  date1.getTime() - date2.getTime();
	    return timeUnit.convert(diffInMillies, TimeUnit.MILLISECONDS);
	}

	
	public String verifySession(String session) {
		//String email = getEmail(session);
		/*
		//1. invalid session
		UserTO userTO = getUser(email);
		System.out.println("USERTO --->" + userTO);
		if (null == userTO) {
			setErrorCode(Constant.INVALID_SESSION_CODE);
			setErrorMessage(Constant.INVALID_SESSION_MESSAGE);
			return Constant.INVALID_SESSION_CODE;
		}
		
		//2. session expired
		if (isExpired(email)) {
			setErrorCode(Constant.EXPIRED_SESSION_CODE);
			setErrorMessage(Constant.EXPIRED_SESSION_MESSAGE);
			return Constant.EXPIRED_SESSION_CODE;
		}
		
		//3. good 
		updateLastOperation(email);
		*/
		return "200";
	}
	
	/**
	 * This method is used to get email from session.
	 * @param session
	 * @return
	 */
	public String getEmail(String session) {
		System.out.println(EncriptUtils.getInstance().decrypt(session));
		if (session == null) return "";
		return EncriptUtils.getInstance().decrypt(session).split("-;-")[0];
	}

	/* *********************** SETTER AND GETTER ********************** */
	/**
	 * @return the errorCode
	 */
	public String getErrorCode() {
		return errorCode;
	}

	/**
	 * @param errorCode the errorCode to set
	 */
	public void setErrorCode(String errorCode) {
		this.errorCode = errorCode;
	}

	/**
	 * @return the errorMessage
	 */
	public String getErrorMessage() {
		return errorMessage;
	}

	/**
	 * @param errorMessage the errorMessage to set
	 */
	public void setErrorMessage(String errorMessage) {
		this.errorMessage = errorMessage;
	}
}
